﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Fast.Threading
{
    [SkipScan]
    public static class AsyncHelper
    {
        /// <summary>
        /// 检查指定的方法是否为异步方法。
        /// </summary>
        /// <param name="method">检查的方法</param>
        public static bool IsAsync(this MethodInfo method)
        {
            Check.NotNull(method, nameof(method));

            return method.ReturnType.IsTaskOrTaskOfT();
        }

        /// <summary>
        /// 检查指定类型是否为 <see cref="Task"/> 类型或 <see cref="Task{}"/> 类型
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool IsTaskOrTaskOfT(this Type type)
        {
            Check.NotNull(type, nameof(type));

            return type == typeof(Task) || (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(Task<>));
        }

        /// <summary>
        /// 检查指定类型是否为 <see cref="Task{}"/> 类型
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool IsTaskOfT(this Type type)
        {
            Check.NotNull(type, nameof(type));

            return type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(Task<>);
        }

        /// <summary>
        /// 如果给定类型为 <see cref="Task"/>，则返回 <see cref="void"/>。
        /// 如果给定类型为 <see cref="Task{T}"/>，则返回 <see href="TResult" />。
        /// 否则返回给定类型。
        /// </summary>
        public static Type UnwrapTask(Type type)
        {
            Check.NotNull(type, nameof(type));

            if (type == typeof(Task))
            {
                return typeof(void);
            }

            if (type.IsTaskOfT())
            {
                return type.GenericTypeArguments[0];
            }

            return type;
        }

        //Nito.AsyncEx.Context组件，待研究
        ///// <summary>
        ///// 同步运行异步方法。
        ///// </summary>
        ///// <param name="func">A function that returns a result</param>
        ///// <typeparam name="TResult">Result type</typeparam>
        ///// <returns>Result of the async operation</returns>
        //public static TResult RunSync<TResult>(Func<Task<TResult>> func)
        //{
        //    return AsyncContext.Run(func);
        //}

        ///// <summary>
        ///// Runs a async method synchronously.
        ///// </summary>
        ///// <param name="action">An async action</param>
        //public static void RunSync(Func<Task> action)
        //{
        //    AsyncContext.Run(action);
        //}
    }
}
